package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.file.service.FileStorageService;
import com.heima.model.common.constants.wemedia.WemediaConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.exception.CustException;
import com.heima.model.common.exception.CustomException;
import com.heima.model.threadLocal.WmThreadLocalUtils;
import com.heima.model.wemedia.dtos.WmMaterialDTO;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Value("${file.oss.prefix}")
    String prefix;

    @Value("${file.oss.web-site}")
    String webSite;

    @Override
    public ResponseResult<WmMaterial> uploadPicture(MultipartFile multipartFile) {
        // 1 参数校验
        if (multipartFile == null || multipartFile.getSize() == 0) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "请上传正确的文件");
        }
        // 2 当前线程中获取用户ID 判断用户是否登录
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NO_OPERATOR_AUTH, "用户未登录");
        }
        // 3 获取文件的原始名称 判断文件的格式
        String originalFilename = multipartFile.getOriginalFilename();
        if (!checkFileSuffix(originalFilename)) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "请上传正确的素材格式,[jpg,jpeg,png,gif]");
        }
        // 4 上传到oss
        String fileId = null;
        try {
            // 重新生成名称,防止文件被覆盖  multipartFile.getInputStream() 获取输入流 不需要自己new
            String filename = UUID.randomUUID().toString().replace("-", "");
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            fileId = fileStorageService.store(prefix, filename + suffix, multipartFile.getInputStream());
            log.info("阿里云OSS 文件 fileId: {}", fileId);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("阿里云文件上传失败 uploadPicture error: {}", e);
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, "服务器繁忙请稍后重试");
        }
        // 3 封装数据并保持到素材库中
        WmMaterial wmMaterial = new WmMaterial();
        wmMaterial.setIsCollection((short) 0); // 是否收藏
        wmMaterial.setType((short) 0); // 图片还是视频
        wmMaterial.setCreatedTime(new Date()); // 创建日期
        // 设置文件id
        wmMaterial.setUrl(fileId);
        wmMaterial.setUserId(user.getId());// 上传文件的用户id
        save(wmMaterial);
        // 前端显示
        wmMaterial.setUrl(webSite + fileId);
        // 4 返回结果
        return ResponseResult.okResult(wmMaterial);
    }

    /**
     * 检查文件格式 目前仅仅支持jpg  jpeg  png  gif 图片的上传
     *
     * @param originalFilename
     * @return
     */
    private boolean checkFileSuffix(String originalFilename) {
        if (StringUtils.isNotBlank(originalFilename)) {
            List<String> allowSuffix = Arrays.asList("jpg", "jpeg", "png", "gif");
            for (String suffix : allowSuffix) {
                if (originalFilename.endsWith(suffix)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 素材列表查询
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(WmMaterialDTO dto) {
        // 1 参数校验 分页 登录
        dto.checkParam();
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN, "用户未登录");
        }
        // 2 查询
        // 2.1 分页条件
        Page<WmMaterial> page = new Page<>(dto.getPage(), dto.getSize());
        // 2.2 查询条件(收藏条件 用户id 发布时间降序)
        LambdaQueryWrapper<WmMaterial> queryWrapper = Wrappers.<WmMaterial>lambdaQuery();
        if (WemediaConstants.COLLECT_MATERIAL.equals(dto.getIsCollection())) {
            // 查询收藏过的素材
            queryWrapper.eq(WmMaterial::getIsCollection, dto.getIsCollection());
        }
        // 只能查询当前用户上传的素材
        queryWrapper.eq(WmMaterial::getUserId, user.getId());
        // 按照发布时间降序排列
        queryWrapper.orderByDesc(WmMaterial::getCreatedTime);
        // 3 执行查询  封装分页返回结果   路径上+ 访问前缀
        IPage<WmMaterial> pageResult = this.page(page, queryWrapper);
        // 获取每个素材的集合
        List<WmMaterial> datas = pageResult.getRecords();
        // 查询每个素材进行处理
        //  路径上 + 访问前缀
        for (WmMaterial data : datas) {
            data.setUrl(webSite + data.getUrl());
        }
        return new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal(), datas);
    }

    /**
     * 根据id删除素材,有关联的素材不可以删除
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult delPicture(Integer id) {
        // 1 参数校验
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2 根据素材id查询素材对象
        WmMaterial wmMaterial = getById(id);
        if (wmMaterial == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "被删除的数据不存在");
        }
        // 3 根据素材id查询该素材是否有关联
        // 因为要查找与素材有关联的数据  所以关联的实体类为WmNewsMaterial
        // 因为数据库中Wm_News_Material存放了与素材有关联的信息
        LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WmNewsMaterial::getMaterialId, id);
        // 执行查询
        Integer count = wmNewsMaterialMapper.selectCount(queryWrapper);
        // 3.1 有关联就不能删除
        if(count > 0){
            // 存在关联
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"存在相关联文件,不能删除!");
        }
        // 3.2 没有则可以删除
        this.removeById(id);
        // 删除图片OSS
        fileStorageService.delete(wmMaterial.getUrl());
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 收藏与取消收藏 0:不收藏 1:收藏
     * @param id
     * @param type
     * @return
     */
    @Override
    public ResponseResult updateStatus(Integer id, Short type) {
        // 1 检查参数
        if(id==null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2 根据id查找素材
        WmMaterial wmMaterial = getById(id);
        if(wmMaterial == null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"素材信息不存在");
        }
        // 3 查看当前用户
        WmUser user = WmThreadLocalUtils.getUser();
        // 4 判断当前用户和素材的上传者是否为用一个人
        Integer userId = wmMaterial.getUserId();
        if(!userId.equals(user.getId())){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"素材拥有者与当前用户不是同一人!");
        }
        // 5 执行状态更改操作
        wmMaterial.setIsCollection(type);
        this.updateById(wmMaterial);
        // 6 返回结果
        return ResponseResult.okResult();
    }
}